// 接口：OOP中，接口是一些具有某些特征的抽象方法的集合，是一种行为规范；派生类必需去实现这些规范，而接口不关心类内部是如何去实现的。
// ts中的接口去C#,java类似，同时还增加了更灵活的接口类型，包括属性，函数，可索引和类等 

// 1，属性接口：对json的约束

//  ts中 方法对参数类型的约束
// function useSome(params: String) {
//     console.log(params);

// }
// // useSome(213); //wrong number不能传给string 类型
// useSome('213'); //ok

//  ts中 方法对json对象参数的约束
// function useSome(userInfo: { 'name': string }) {
//     console.log(userInfo);
// }
// // useSome('张三丰'); //wrong 
// useSome({ 'name': '张三丰' }); //ok
// // useSome({ 'name': '张三丰', 'age': 20 }); //wrong
// let u = { 'name': '张三丰', 'age': 20 }
// useSome(u); //ok

//interface 声明接口，对方法中传入参数对象的约束就是属性接口
// interface Fullname {
//     firstName: string;
//     lastName: string;
// }
// // 参数是一个接口类型，而且必需是一个{firstName,lastName}类型的对象
// function userInfo(info: Fullname) {
//     console.log(info.firstName + ' -- ' + info.lastName);
// }
// userInfo({ firstName: '张', lastName: '一三' })
// // userInfo({ firstName: '张', lastName: '一三', age: 20 })    //wrong
// let uobj = { firstName: '张', lastName: '一三', age: 20 };
// userInfo(uobj);                                               //right

// 接口 可选参数
// interface Options {
//     type: string;
//     url: string;
//     data?: string;
//     dataType: string;
// }
// // 原生封装的ajax
// function ajax(options: Options) {
//     let xhr = new XMLHttpRequest();
//     xhr.open(options.type, options.url, true);
//     if (options.data)
//         xhr.send(options.data);
//     else
//         xhr.send();
//     xhr.onreadystatechange = function () {
//         if (xhr.readyState == 4 && xhr.status == 200) {
//             console.log('success');
//             if (options.dataType == 'json')
//                 console.log('json: ', JSON.parse(xhr.responseText));
//             else
//                 console.log(xhr.responseText);
//         }
//     }
// }

// let reqopt = {
//     type: 'get',
//     url: 'http://a.itying.com/api/productlist',
//     // data: '',
//     dataType: 'json'
// }
// ajax(reqopt);

//2，函数类型接口：对方法传入的参数、返回值进行约束
// interface Encrypt {
//     (key: string, value: string): string
// }

// let md5: Encrypt = function (key: string, value: string): string {
//     return key + value;
// }
// let sha1 = function (key: string, value: string): string { //这里的接口类型是可以省略的，所以我没明白这里函数类型接口有什么意义，加了接口类型后面的参数类型声明和返回值类型声明还是要写
//     return key + value;
// }
// console.log(sha1('hello', ' vue'));

// 3，可索引接口：数组/对象的约束（不常用）
// ts 定义数组的方式
// let arr: string[] = ['a', 'b', 'c', 'd']
// let arrb: Array<string> = ['a', 'b', 'c', 'd']
// 自定义数组接口类型
// interface UserArr{
//     [index:number]:string
// }
// let arr:UserArr=['aa','bb','cc']
// let arrb:Array<UserArr>=['gg','cc','ss']
// console.log(arr);
// console.log(arrb);
// 对对象的约束
// interface UserObj {
//     [index: string]: string
// }
// let ar: UserObj = { 'name': '张三丰' }
// console.log(ar);

// 4，类类型接口：对类的约束，和抽象类类似
// 类上使用implements 实现接口
// interface Voice {
//     type: string;
//     make(str: string): string;
// }

// class Speaker implements Voice {
//     type: string;
//     constructor(str: string) {
//         this.type = str
//     }
//     make() {    //子类实现接口方法可以不加参数
//         console.log(this.type + ' make voice');
//         return 'end';
//     }
// }
// let s = new Speaker('speaker')
// console.log(s.make());

// class Singer implements Voice {
//     type: string;
//     constructor(str: string) {
//         this.type = str
//     }
//     make(name: string) {    
//         console.log(name + ': ' + this.type + ' make voice');
//         return 'end';
//     }
// }
// let sn = new Singer('singer')
// console.log(sn.make('小红'));

// 5，接口扩展：接口可以通过继承其他接口扩展
// 接口使用extends 继承接口
interface Animal {
    eat(): void;
}
interface AdvancedAnimal extends Animal {
    work(): void;
}

class Programer {
    _name: string;
    constructor(name: string) {
        this._name = name;
    }
    code() {
        console.log(this._name + ' can code')
    }
}

// 继承类并且实现接口
class Person extends Programer implements AdvancedAnimal {
    eat(): void {
        console.log(this._name + ' can eat');
    }
    work(): void {
        console.log(this._name + ' can work');
    }
    constructor(name: string) {
        super(name)
    }
}
let p = new Person('张小三')
p.eat();
p.work();
p.code();